/**
 * 通用分页加载工具类
 *
 * 设计理念：
 * - 工具类只负责维护分页状态和逻辑，不持有页面实例
 * - 通过 onStateChange 回调通知外部状态变化，由外部决定如何更新页面
 * - 网络请求由外部通过 onLoadData 实现
 * - 符合"控制反转"原则，工具类不依赖具体的页面实现
 *
 * 优点：
 * - 工具类职责单一，易于测试和维护
 * - 不持有页面引用，避免潜在的内存泄漏
 * - 灵活性高，可用于不同框架（微信小程序、Vue、React等）
 *
 * @author slc
 * @date 2025-01-10
 */

class PaginationUtil {
    constructor(options = {}) {
        // 默认配置
        this.config = {
            // 分页参数
            pageSize: 10,
            initialPageNum: 1,    // 初始页码（默认从1开始，有些后端从0开始）

            // 回调函数
            onLoadData: null,      // 数据加载函数，接收(pageNum, pageSize, resultCallback)，通过resultCallback回调设置数据
            onStateChange: null,   // 状态变化回调，接收(state)，由外部实现页面数据更新
            onRefreshComplete: null, // 下拉刷新完成回调，由外部实现停止刷新动画的逻辑

            ...options
        };

        // 内部状态
        this.state = {
            pageNum: this.config.initialPageNum,  // 当前页码
            pageSize: this.config.pageSize,
            list: [],             // 数据列表
            total: 0,             // 总数据量
            hasMore: true,        // 是否有更多数据
            loading: false,       // 加载状态
            loadingMore: false    // 加载更多状态
        };
    }

    /**
     * 设置默认数据
     */
    setDefaultData() {
        this.state = {
            pageNum: this.config.initialPageNum,
            pageSize: this.config.pageSize,
            list: [],
            total: 0,
            hasMore: true,
            loading: false,
            loadingMore: false
        };
    }

    /**
     * 通知状态变化
     * 当工具类内部状态改变时，调用此方法通知外部
     */
    notifyStateChange() {
        if (this.config.onStateChange) {
            this.config.onStateChange({
                list: this.state.list,
                loading: this.state.loading,
                loadingMore: this.state.loadingMore,
                hasMore: this.state.hasMore,
                pageNum: this.state.pageNum,
                total: this.state.total
            });
        }
    }

    /**
     * 处理响应数据
     * 外部调用此方法，将后端返回的数据传入
     *
     * @param {Object} response 后端响应数据
     * @param {Array} response.rows 数据列表
     * @param {Number} response.total 总数据量
     * @param {Boolean} options.reset 是否重置列表（默认false，追加数据）
     */
    handleResponse({ dataList = [], total = 0 }, { reset = false } = {}) {
        // 更新数据列表和页码
        if (reset) {
            // 重置：清空列表，恢复初始页码
            this.state.list = dataList;
        } else {
            // 追加：合并数据，页码+1
            this.state.list = [...this.state.list, ...dataList];
        }
        this.state.pageNum++;
        // 更新总数
        this.state.total = total;

        // 计算是否还有更多数据
        this.state.hasMore = this.state.list.length < total;

        // 通知状态变化
        this.notifyStateChange();

        return {
            list: this.state.list,
            total: this.state.total,
            hasMore: this.state.hasMore,
            pageNum: this.state.pageNum
        };
    }

    /**
     * 重置状态
     * 用于下拉刷新等场景
     */
    reset() {
        this.state.pageNum = this.config.initialPageNum;
        this.state.list = [];
        this.state.total = 0;
        this.state.hasMore = true;
        this.notifyStateChange();
    }

    /**
     * 加载数据（首次加载或刷新）
     * 内部会调用 onLoadData 函数，传入 pageNum、pageSize 和 resultCallback 回调
     * @param {Boolean} isRefresh 是否是下拉刷新触发的加载
     */
    loadData(isRefresh = false) {
        if (!this.config.onLoadData) {
            console.error('未配置 onLoadData 函数');
            return;
        }

        // 重置状态
        this.reset();
        this.setLoading(true);

        // 调用外部提供的加载函数，传入 resultCallback 回调
        this.config.onLoadData(this.state.pageNum, this.state.pageSize, (result) => {
            // 处理返回的数据
            this.handleResponse({
                dataList: result.dataList || [],
                total: result.total || 0
            }, { reset: true });

            this.setLoading(false);

            // 如果是下拉刷新触发的，且配置了刷新完成回调，则调用
            if (isRefresh && this.config.onRefreshComplete) {
                this.config.onRefreshComplete();
            }
        });
    }

    /**
     * 加载更多数据
     */
    loadMore() {
        if (!this.config.onLoadData) {
            console.error('未配置 onLoadData 函数');
            return;
        }

        if (!this.canLoadMore()) {
            console.log('没有更多数据或正在加载中');
            return;
        }

        this.setLoadingMore(true);

        // 调用外部提供的加载函数，传入 resultCallback 回调
        this.config.onLoadData(this.state.pageNum, this.state.pageSize, (result) => {
            this.handleResponse({
                dataList: result.dataList || [],
                total: result.total || 0
            });

            this.setLoadingMore(false);
        });
    }

    /**
     * 刷新数据（下拉刷新）
     * 刷新完成后会调用 onRefreshComplete 回调，由外部实现停止刷新动画
     */
    refresh() {
        this.loadData(true);  // 传入 true 表示是下拉刷新触发的
    }

    /**
     * 检查是否可以加载更多
     */
    canLoadMore() {
        return this.state.hasMore && !this.state.loadingMore && !this.state.loading;
    }

    /**
     * 获取当前页码
     */
    getCurrentPage() {
        return this.state.pageNum;
    }

    /**
     * 获取分页大小
     */
    getPageSize() {
        return this.state.pageSize;
    }

    /**
     * 获取请求参数
     * 返回用于网络请求的分页参数对象
     */
    getRequestParams() {
        return {
            pageNum: this.state.pageNum,
            pageSize: this.state.pageSize
        };
    }

    /**
     * 获取当前列表
     */
    getList() {
        return this.state.list;
    }

    /**
     * 获取总数
     */
    getTotal() {
        return this.state.total;
    }

    /**
     * 是否有更多数据
     */
    hasMore() {
        return this.state.hasMore;
    }

    /**
     * 是否正在加载
     */
    isLoading() {
        return this.state.loading;
    }

    /**
     * 是否正在加载更多
     */
    isLoadingMore() {
        return this.state.loadingMore;
    }

    /**
     * 设置加载状态
     */
    setLoading(loading) {
        this.state.loading = loading;
        this.notifyStateChange();
    }

    /**
     * 设置加载更多状态
     */
    setLoadingMore(loading) {
        this.state.loadingMore = loading;
        this.notifyStateChange();
    }

    /**
     * 获取当前状态快照
     */
    getState() {
        return {
            pageNum: this.state.pageNum,
            pageSize: this.state.pageSize,
            total: this.state.total,
            hasMore: this.state.hasMore,
            loading: this.state.loading,
            loadingMore: this.state.loadingMore,
            listLength: this.state.list.length
        };
    }

    /**
     * 销毁实例
     */
    destroy() {
        this.state = null;
        this.config = null;
    }
}

/**
 * 创建分页工具实例
 *
 * @param {Object} options 配置选项
 * @param {Number} options.pageSize 每页数量，默认10
 * @param {Number} options.initialPageNum 初始页码，默认1（适用于Java后端）
 * @param {Function} options.onLoadData 数据加载函数，接收(pageNum, pageSize, resultCallback)
 * @param {Function} options.onStateChange 状态变化回调，接收(state)，用于更新页面数据
 * @param {Function} options.onRefreshComplete 下拉刷新完成回调
 * @returns {PaginationUtil} 分页工具实例
 *
 * @example
 * // 基本用法
 * this.paginationUtil = createPaginationUtil({
 *   pageSize: 10,
 *
 *   // 加载数据（由工具类调用）
 *   onLoadData: (pageNum, pageSize, resultCallback) => {
 *     wx.apiRequest({
 *       url: '/api/list',
 *       data: { pageNum, pageSize },
 *       success: (res) => {
 *         // 处理数据并通过回调返回
 *         resultCallback({
 *           dataList: res.data.rows,
 *           total: res.data.total
 *         });
 *       }
 *     });
 *   },
 *
 *   // 状态变化时更新页面（由工具类调用）
 *   onStateChange: (state) => {
 *     this.setData({
 *       list: state.list,
 *       loading: state.loading,
 *       loadingMore: state.loadingMore,
 *       hasMore: state.hasMore
 *     });
 *   },
 *
 *   // 下拉刷新完成（由工具类调用）
 *   onRefreshComplete: () => {
 *     wx.stopPullDownRefresh();
 *   }
 * });
 *
 * // 在页面生命周期中使用
 * onLoad() {
 *   this.paginationUtil.loadData();  // 首次加载
 * }
 *
 * onReachBottom() {
 *   this.paginationUtil.loadMore();  // 加载更多
 * }
 *
 * onPullDownRefresh() {
 *   this.paginationUtil.refresh();   // 下拉刷新
 * }
 */
function createPaginationUtil(options = {}) {
    return new PaginationUtil(options);
}

module.exports = {
    PaginationUtil,
    createPaginationUtil
};
